package cn.agiledata.bank.audit.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import cn.agiledata.bank.audit.dao.IAuditOperandTypeDao;
import cn.agiledata.bank.audit.dao.IAuditOperationDao;
import cn.agiledata.bank.audit.dao.IAuditRuleDao;
import cn.agiledata.bank.audit.exception.AuditException;
import cn.agiledata.bank.audit.logic.AuditGroupWrapper;
import cn.agiledata.bank.audit.logic.AuditLevel;
import cn.agiledata.bank.audit.logic.AuditOperationWrapper;
import cn.agiledata.bank.audit.logic.AuditRuleWrapper;
import cn.agiledata.bank.audit.logic.AuditStatus;
import cn.agiledata.bank.audit.logic.HistoryAuditOperationWrapper;
import cn.agiledata.bank.common.servlet.InitForString;
import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.hibernateBean.Account;
import cn.agiledata.bank.hibernateBean.AuditGroup;
import cn.agiledata.bank.hibernateBean.AuditOperandType;
import cn.agiledata.bank.hibernateBean.AuditOperation;
import cn.agiledata.bank.hibernateBean.AuditRule;
import cn.agiledata.bank.hibernateBean.AuditStep;
import cn.agiledata.bank.hibernateBean.HistoryAuditOperation;
import cn.agiledata.bank.hibernateBean.Operator;
import cn.agiledata.bank.hibernateBean.RecentAuditOperation;
import cn.agiledata.bank.hibernateBean.Sysbook;
import cn.agiledata.bank.hibernateBean.UserInfo;

/**
 * 
 * @author 马贤波
 * 
 */
public final class AuditServiceImpl implements AuditService {
    private IAuditOperandTypeDao auditOperandTypeDao;

    private IAuditRuleDao auditRuleDao;

    private IAuditOperationDao auditOperationDao;

    private String auditStepNamePrefix;

    public AuditServiceImpl() {
    }

    public void setAuditStepNamePrefix(String auditStepNamePrefix) {
        this.auditStepNamePrefix = auditStepNamePrefix;
    }

    public boolean agree(AuditOperandType auditOperandType,
            long auditOperandId, Operator operator, String attitude)
            throws AuditException {
        if (auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_SYSTEM_TYPE;
        }
        String auditorId = operator.getId().toString();
        return agree(auditOperandType, auditOperandId, auditorId, attitude);
    }

    private boolean agree(AuditOperandType auditOperandType,
            long auditOperandId, String auditorId, String attitude)
            throws AuditException {
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        if (rao == null) {
            // 此处rao不应该为null，如果为null，则说明审核数据与业务数据不一致，存在问题
            throw AuditException.NO_AUDIT_RECORD;
        }
        AuditOperationWrapper raoWrapper = new AuditOperationWrapper(rao);
        AuditStatus previousStatus = raoWrapper.getPostStatus();
        // 如果审核状态低于初始状态，或者高于终审状态，则不能进行同意操作
        if (previousStatus.compareTo(AuditStatus.STATUS_PRIMARY) < 0
                || previousStatus.compareTo(AuditStatus.STATUS_FINAL) >= 0) {
            throw AuditException.AUDIT_STATUS_MISMATCH;
        }
        AuditRule auditRule = rao.getAuditRule();
        Set auditSteps = auditRule.getAuditSteps();
        AuditGroup auditGroup = getAuditGroupByStatus(auditSteps,
                previousStatus);
        AuditRuleWrapper auditRuleWrapper = new AuditRuleWrapper(auditRule);
        AuditLevel maxAuditLevel = auditRuleWrapper.maxAuditLevel();
        AuditStatus postStatus = previousStatus.compareTo(AuditStatus
                .getAuditStatus(maxAuditLevel)) < 0 ? previousStatus
                .nextAuditStatus() : AuditStatus.STATUS_FINAL;
        setAuditOperation(rao, auditOperandId, auditRule, auditGroup,
                auditorId, previousStatus, postStatus, attitude);
        update(rao);
        return raoWrapper.isFinal();
    }

    public boolean agree(AuditOperandType auditOperandType,
            long auditOperandId, UserInfo user, String attitude)
            throws AuditException {
        if (!auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_CORP_TYPE;
        }
        String auditorId = user.getId().toString();
        return agree(auditOperandType, auditOperandId, auditorId, attitude);
    }

    public void create(AuditOperandType auditOperandType, long auditOperandId,
            Account account) throws AuditException {
        if (!auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_CORP_TYPE;
        }
        if (!Constant.ACCOUNT_TYPE_BUYER.equals(account.getAccountType())) {
            throw AuditException.PERSON_ACCOUNT_AUTHORITY;
        }
        String auditorId = account.getId().toString();
        Long accountId = null;
        if (isCorpAccount(account)) { // 企业客户设置accountId，以查找该客户下的审核规则
            accountId = account.getId();
        }
        create(auditOperandType, auditOperandId, accountId, auditorId);
    }

    private void create(AuditOperandType auditOperandType, long auditOperandId,
            Long accountId, String auditorId) throws AuditException {
        AuditRule auditRule = getValidAuditRule(accountId, auditOperandType);
        if (!validAuditRule(auditRule)) {
            throw AuditException.NO_VALID_RULE;
        }
        Set auditSteps = auditRule.getAuditSteps();
        AuditStatus previousStatus = AuditStatus.STATUS_PRIMARY;
        AuditGroup auditGroup = getAuditGroupByStatus(auditSteps,
                previousStatus);
        RecentAuditOperation rao = new RecentAuditOperation();
        AuditStatus postStatus = AuditStatus.STATUS_PRIMARY;
        setAuditOperation(rao, auditOperandId, auditRule, auditGroup,
                auditorId, previousStatus, postStatus, null);
        update(rao);
    }

    public void create(AuditOperandType auditOperandType, long auditOperandId,
            Operator operator) throws AuditException {
        if (auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_SYSTEM_TYPE;
        }
        Long accountId = operator.getAccount().getId();
        String auditorId = operator.getId().toString();
        create(auditOperandType, auditOperandId, accountId, auditorId);
    }

    public void create(AuditOperandType auditOperandType, long auditOperandId,
            UserInfo user) throws AuditException {
        if (!auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_CORP_TYPE;
        }
        String auditorId = user.getId().toString();
        create(auditOperandType, auditOperandId, null, auditorId);
    }

    private void cancel(AuditOperandType auditOperandType, long auditOperandId,
            String auditorId, String attitude) throws AuditException {
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        if (rao == null) {
            // 此处rao不应该为null，如果为null，则说明审核数据与业务数据不一致，存在问题
            throw AuditException.NO_AUDIT_RECORD;
        }
        AuditStatus previousStatus = new AuditOperationWrapper(rao)
                .getPostStatus();
        // 已取消和未知状态的审核对象不能进行取消操作
        if (previousStatus == AuditStatus.STATUS_CANCEL
                || previousStatus == AuditStatus.STATUS_UNKNOWN) {
            throw AuditException.AUDIT_STATUS_MISMATCH;
        }
        AuditRule auditRule = rao.getAuditRule();
        Set auditSteps = auditRule.getAuditSteps();
        AuditGroup auditGroup = getAuditGroupByStatus(auditSteps,
                previousStatus);
        AuditStatus postStatus = AuditStatus.STATUS_CANCEL;
        setAuditOperation(rao, auditOperandId, auditRule, auditGroup,
                auditorId, previousStatus, postStatus, attitude);
        update(rao);
    }

    public void cancel(AuditOperandType auditOperandType, long auditOperandId,
            UserInfo user, String attitude) throws AuditException {
        if (!auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_CORP_TYPE;
        }
        String auditorId = user.getId().toString();
        cancel(auditOperandType, auditOperandId, auditorId, attitude);
    }

    private AuditGroup getAuditGroupByStatus(Set auditStepSet,
            AuditStatus auditStatus) {
        AuditStep auditStep = getAuditStepByStatus(auditStepSet, auditStatus);
        return auditStep == null ? null : auditStep.getAuditGroup();
    }

    /**
     * 分页查询正在审核中（非未知、被取消、初始、被拒绝、终审完毕）的最近审核操作
     */
    private RecentAuditOperation[] getAuditingRecentAuditOperations(
            AuditOperandType[] auditOperandTypes, int beginIndex, int maxTotal) {
        return this.auditOperationDao.getAuditingRecentAuditOperations(
                auditOperandTypes, beginIndex, maxTotal);
    }

    public AuditOperandType getAuditOperandType(String className,
            String actionFlag) {
        return this.auditOperandTypeDao.getAuditOperandType(className,
                actionFlag);
    }

    public String getAuditStatusLabel(AuditOperandType auditOperandType,
            long auditOperandId, AuditStatus auditStatus) {
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        if (auditStatus == AuditStatus.STATUS_PRIMARY
                || auditStatus == AuditStatus.STATUS_REJECTED
                || auditStatus == AuditStatus.STATUS_FINAL
                || auditStatus == AuditStatus.STATUS_UNKNOWN) {
            String typeName = "NORMAL_AUDIT_STATUS";
            List auditStatusList = (List) InitForString.dataDictMap
                    .get(typeName);
            for (int i = 0; i < auditStatusList.size(); i++) {
                Sysbook sysbook = (Sysbook) auditStatusList.get(i);
                int value = Integer.parseInt(sysbook.getId().getListId());
                if (auditStatus == AuditStatus.getAuditStatus(value)) {
                    return sysbook.getListName();
                }
            }
        } else {
            Set auditSteps = rao.getAuditRule().getAuditSteps();
            AuditStep auditStep = getAuditStepByStatus(auditSteps, auditStatus);
            if (auditStep != null) {
                return this.auditStepNamePrefix + auditStep.getName();
            }
        }
        return "";
    }

    public String getAuditStatusLabel(AuditOperandType auditOperandType,
            long auditOperandId, int auditStatus) {
        return getAuditStatusLabel(auditOperandType, auditOperandId,
                AuditStatus.getAuditStatus(auditStatus));
    }

    private AuditStep getAuditStepByStatus(Set auditSteps,
            AuditStatus auditStatus) {
        for (Iterator it = auditSteps.iterator(); it.hasNext();) {
            AuditStep auditStep = (AuditStep) it.next();
            AuditLevel auditLevel = AuditLevel.getAuditLevel(auditStep
                    .getLevel());
            if (AuditStatus.getAuditStatus(auditLevel).equals(auditStatus)) {
                return auditStep;
            }
        }
        return null;
    }

    public RecentAuditOperation[] getAuthoritativeRecentAuditOperations(
            AuditOperandType auditOperandType, UserInfo user, int beginIndex,
            int maxTotal) {
        return getAuthoritativeRecentAuditOperations(
                new AuditOperandType[] { auditOperandType }, user, beginIndex,
                maxTotal);
    }

    /**
     * 分页查询指定前台操作员或后台用户具有审核权限的所有审核对象的最近审核操作清单
     * 
     * @param auditOperandTypes
     *            审核对象类型清单。支持查询多种审核对象类型下的审核对象的最近审核操作
     * @param operatorOrUser
     *            前台操作员或后台用户。类型只能为Operator或UserInfo，否则将返回空的结果清单
     */
    private RecentAuditOperation[] getAuthoritativeRecentAuditOperations(
            AuditOperandType[] auditOperandTypes, Object operatorOrUser,
            int beginIndex, int maxTotal) {
        List resultList = new ArrayList();
        RecentAuditOperation[] raos = getAuditingRecentAuditOperations(
                auditOperandTypes, beginIndex, maxTotal);
        for (int total = 0; true; raos = getAuditingRecentAuditOperations(
                auditOperandTypes, beginIndex, maxTotal)) {
            if (raos.length == 0) { // 如果后续未查出审核中的当前审核操作，则跳出循环返回结果
                break;
            }
            for (int i = 0; i < raos.length; i++) {
                AuditOperandType aot = raos[i].getAuditRule()
                        .getAuditOperandType();
                long auditOperandId = raos[i].getAuditOperandId().longValue();
                boolean hasAuditAuthority = false;
                if (operatorOrUser instanceof Operator) {
                    hasAuditAuthority = hasAuditAuthority(aot, auditOperandId,
                            (Operator) operatorOrUser);
                } else if (operatorOrUser instanceof UserInfo) {
                    hasAuditAuthority = hasAuditAuthority(aot, auditOperandId,
                            (UserInfo) operatorOrUser);
                } else {
                    return new RecentAuditOperation[0];
                }
                if (hasAuditAuthority) {
                    resultList.add(raos[i]);
                    total++;
                    if (beginIndex > 0 && maxTotal > 0 && total >= maxTotal) { // 总数达到指定数量，跳出循环
                        break;
                    }
                }
            }
            if (beginIndex <= 0 || maxTotal <= 0) { // 未分页查询直接跳出循环
                break;
            }
            beginIndex += maxTotal;
            maxTotal -= total;
        }
        return (RecentAuditOperation[]) resultList
                .toArray(new RecentAuditOperation[0]);
    }

    public RecentAuditOperation[] getAuthoritativeRecentAuditOperations(
            AuditOperandType[] auditOperandTypes, Operator operator,
            int beginIndex, int maxTotal) {
        return getAuthoritativeRecentAuditOperations(auditOperandTypes,
                operator, beginIndex, maxTotal);
    }

    public long getAuthoritativeRecentAuditOperationsTotal(
            AuditOperandType auditOperandType, UserInfo user) {
        return getAuthoritativeRecentAuditOperationsTotal(
                new AuditOperandType[] { auditOperandType }, user);
    }

    /**
     * 查询指定前台操作员或后台用户具有审核权限的所有审核对象的最近审核操作的总数
     * 
     * @param auditOperandTypes
     *            审核对象类型清单。支持查询多种审核对象类型下的审核对象的最近审核操作的总数
     * @param operatorOrUser
     *            前台操作员或后台用户。类型只能为Operator或UserInfo，否则将返回0
     */
    private long getAuthoritativeRecentAuditOperationsTotal(
            AuditOperandType[] auditOperandTypes, Object operatorOrUser) {
        long total = 0;
        RecentAuditOperation[] raos = getAuditingRecentAuditOperations(
                auditOperandTypes, 0, 0);
        for (int i = 0; i < raos.length; i++) {
            AuditOperandType aot = raos[i].getAuditRule().getAuditOperandType();
            long auditOperandId = raos[i].getAuditOperandId().longValue();
            boolean hasAuditAuthority = false;
            if (operatorOrUser instanceof Operator) {
                hasAuditAuthority = hasAuditAuthority(aot, auditOperandId,
                        (Operator) operatorOrUser);
            } else if (operatorOrUser instanceof UserInfo) {
                hasAuditAuthority = hasAuditAuthority(aot, auditOperandId,
                        (UserInfo) operatorOrUser);
            } else {
                return 0;
            }
            if (hasAuditAuthority) {
                total++;
            }
        }
        return total;
    }

    public long getAuthoritativeRecentAuditOperationsTotal(
            AuditOperandType[] auditOperandTypes, Operator operator) {
        return getAuthoritativeRecentAuditOperationsTotal(auditOperandTypes,
                operator);
    }

    public AuditStatus getCurrentAuditStatus(AuditOperandType auditOperandType,
            long auditOperandId) {
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        return new AuditOperationWrapper(rao).getPostStatus();
    }

    public HistoryAuditOperation[] getHistoryAuditOperations(
            AuditOperandType auditOperandType, AuditStatus[] postStatuses,
            UserInfo[] users, Date beginAuditTime, Date endAuditTime,
            int beginIndex, int maxTotal) {
        if (!auditOperandType.isSystemType())
            return new HistoryAuditOperation[0];
        return this.auditOperationDao.getHistoryAuditOperations(
                auditOperandType, postStatuses, users, beginAuditTime,
                endAuditTime, beginIndex, maxTotal);
    }

    public HistoryAuditOperation[] getHistoryAuditOperations(
            AuditOperandType auditOperandType, long auditOperandId) {
        return this.auditOperationDao.getHistoryAuditOperations(
                auditOperandType, auditOperandId);
    }

    public HistoryAuditOperation[] getHistoryAuditOperationsOfLastFlow(
            AuditOperandType auditOperandType, long auditOperandId) {
        HistoryAuditOperation[] haos = getHistoryAuditOperations(
                auditOperandType, auditOperandId);
        if (haos.length == 0)
            return haos;
        List resultList = new ArrayList();
        // 从初始结果集的末尾向头部依次查找
        for (int i = haos.length - 1; i >= 0; i--) {
            HistoryAuditOperationWrapper haow = new HistoryAuditOperationWrapper(
                    haos[i]);
            AuditStatus auditStatus = haow.getPostStatus();
            if (auditStatus != AuditStatus.STATUS_REJECTED
                    && auditStatus != AuditStatus.STATUS_PRIMARY) {
                // 非拒绝和非初始状态的审核操作加入结果列表
                resultList.add(haos[i]);
            } else {
                // 一旦找到一条拒绝或初始状态的审核操作，立即停止查找
                break;
            }
        }
        // 反转结果列表中的对象排序
        int size = resultList.size();
        HistoryAuditOperation[] result = new HistoryAuditOperation[size];
        for (int i = 0; i < size; i++) {
            result[i] = (HistoryAuditOperation) resultList.get(size - 1 - i);
        }
        return result;
    }

    public long getHistoryAuditOperationsTotal(
            AuditOperandType auditOperandType, AuditStatus[] postStatuses,
            UserInfo[] users, Date beginAuditTime, Date endAuditTime) {
        if (!auditOperandType.isSystemType())
            return 0;
        return this.auditOperationDao.getHistoryAuditOperationsTotal(
                auditOperandType, postStatuses, users, beginAuditTime,
                endAuditTime);
    }

    public RecentAuditOperation getRecentAuditOperation(
            AuditOperandType auditOperandType, long auditOperandId) {
        return this.auditOperationDao.getRecentAuditOperation(auditOperandType,
                auditOperandId);
    }

    private AuditRule getValidAuditRule(Long accountId,
            AuditOperandType auditOperandType) {
        return this.auditRuleDao.getValidAuditRule(accountId, auditOperandType);
    }

    public boolean hasAuditAuthority(AuditOperandType auditOperandType,
            long auditOperandId, Operator operator) {
        if (auditOperandType.isSystemType()) {
            // 企业操作员对后台系统审核对象类型不具有审核权限
            return false;
        }
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        if (rao == null) {
            // 此处rao不应该为null，如果为null，则说明审核数据与业务数据不一致，存在问题
            return false;
        }
        Set auditSteps = rao.getAuditRule().getAuditSteps();
        // 如果审核规则没有审核步骤，则允许所有操作员审核
        if (auditSteps == null || auditSteps.isEmpty()) {
            return true;
        }
        AuditStatus auditStatus = new AuditOperationWrapper(rao)
                .getPostStatus();
        AuditGroup auditGroup = getAuditGroupByStatus(auditSteps, auditStatus);
        return auditGroup != null
                && new AuditGroupWrapper(auditGroup).containsOperator(operator);
    }

    public boolean hasAuditAuthority(AuditOperandType auditOperandType,
            long auditOperandId, UserInfo user) {
        if (!auditOperandType.isSystemType()) {
            // 后台用户对前台系统审核对象类型不具有审核权限
            return false;
        }
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        if (rao == null) {
            // 此处rao不应该为null，如果为null，则说明审核数据与业务数据不一致，存在问题
            return false;
        }
        Set auditSteps = rao.getAuditRule().getAuditSteps();
        // 如果审核规则没有审核步骤，则允许所有后台用户审核
        if (auditSteps == null || auditSteps.isEmpty()) {
            return true;
        }
        AuditStatus auditStatus = new AuditOperationWrapper(rao)
                .getPostStatus();
        AuditGroup auditGroup = getAuditGroupByStatus(auditSteps, auditStatus);
        return auditGroup != null
                && new AuditGroupWrapper(auditGroup).containsUser(user);
    }

    public boolean isFinished(AuditOperandType auditOperandType,
            long auditOperandId) {
        AuditOperation auditOperation = getRecentAuditOperation(
                auditOperandType, auditOperandId);
        if (auditOperation == null) {
            // 无审核记录，则非终审状态
            return false;
        }
        return new AuditOperationWrapper(auditOperation).isFinal();
    }

    public boolean isRejected(AuditOperandType auditOperandType,
            long auditOperandId) {
        AuditOperation auditOperation = getRecentAuditOperation(
                auditOperandType, auditOperandId);
        if (auditOperation == null) {
            // 无审核记录，则非拒绝状态
            return false;
        }
        return new AuditOperationWrapper(auditOperation).isRejected();
    }

    private void reject(AuditOperandType auditOperandType, long auditOperandId,
            String auditorId, String attitude) throws AuditException {
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        if (rao == null) {
            // 此处rao不应该为null，如果为null，则说明审核数据与业务数据不一致，存在问题
            throw AuditException.NO_AUDIT_RECORD;
        }
        AuditStatus previousStatus = new AuditOperationWrapper(rao)
                .getPostStatus();
        // 只有待审核的审核对象才能被拒绝
        if (previousStatus.compareTo(AuditStatus.STATUS_SUBMITTED) < 0
                || previousStatus.compareTo(AuditStatus.STATUS_FINAL) >= 0) {
            throw AuditException.AUDIT_STATUS_MISMATCH;
        }
        AuditRule auditRule = rao.getAuditRule();
        Set auditSteps = auditRule.getAuditSteps();
        AuditGroup auditGroup = getAuditGroupByStatus(auditSteps,
                previousStatus);
        AuditStatus postStatus = AuditStatus.STATUS_REJECTED;
        setAuditOperation(rao, auditOperandId, auditRule, auditGroup,
                auditorId, previousStatus, postStatus, attitude);
        update(rao);
    }

    public void reject(AuditOperandType auditOperandType, long auditOperandId,
            Operator operator, String attitude) throws AuditException {
        if (auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_SYSTEM_TYPE;
        }
        String auditorId = operator.getId().toString();
        reject(auditOperandType, auditOperandId, auditorId, attitude);
    }

    public void reject(AuditOperandType auditOperandType, long auditOperandId,
            UserInfo user, String attitude) throws AuditException {
        if (!auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_CORP_TYPE;
        }
        String auditorId = user.getId().toString();
        reject(auditOperandType, auditOperandId, auditorId, attitude);
    }

    private void reset(AuditOperandType auditOperandType, long auditOperandId,
            String auditorId, String attitude) throws AuditException {
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        if (rao == null) {
            // 此处rao不应该为null，如果为null，则说明审核数据与业务数据不一致，存在问题
            throw AuditException.NO_AUDIT_RECORD;
        }
        AuditRule auditRule = rao.getAuditRule();
        Set auditSteps = auditRule.getAuditSteps();
        AuditStatus previousStatus = new AuditOperationWrapper(rao)
                .getPostStatus();
        // 只有终审完毕才能进行重置操作
        if (previousStatus != AuditStatus.STATUS_FINAL) {
            throw AuditException.AUDIT_STATUS_MISMATCH;
        }
        AuditGroup auditGroup = getAuditGroupByStatus(auditSteps,
                previousStatus);
        AuditStatus postStatus = AuditStatus.STATUS_PRIMARY;
        setAuditOperation(rao, auditOperandId, auditRule, auditGroup,
                auditorId, previousStatus, postStatus, attitude);
        update(rao);
    }

    public void reset(AuditOperandType auditOperandType, long auditOperandId,
            UserInfo user, String attitude) throws AuditException {
        if (!auditOperandType.isSystemType()) {
            throw AuditException.CANNOT_AUDIT_CORP_TYPE;
        }
        String auditorId = user.getId().toString();
        reset(auditOperandType, auditOperandId, auditorId, attitude);
    }

    public boolean requiredSystemAudit(AuditOperandType auditOperandType) {
        if (!auditOperandType.isSystemType())
            return false;
        AuditRule auditRule = getValidAuditRule(null, auditOperandType);
        return validAuditRule(auditRule);
    }

    public boolean requiredUserAudit(long accountId,
            AuditOperandType auditOperandType) {
        if (auditOperandType.isSystemType())
            return false;
        AuditRule auditRule = getValidAuditRule(new Long(accountId),
                auditOperandType);
        return validAuditRule(auditRule);
    }

    public void setAuditOperandTypeDao(IAuditOperandTypeDao auditOperandTypeDao) {
        this.auditOperandTypeDao = auditOperandTypeDao;
    }

    private void setAuditOperation(AuditOperation rao, long auditOperandId,
            AuditRule auditRule, AuditGroup auditGroup, String auditorId,
            AuditStatus previousStatus, AuditStatus postStatus, String attitude) {
        rao.setAuditOperandId(new Long(auditOperandId));
        rao.setAuditRule(auditRule);
        rao.setAuditGroup(auditGroup);
        rao.setPreviousStatus(previousStatus.getValue());
        rao.setPostStatus(postStatus.getValue());
        rao.setAttitude(attitude);
        rao.setUpdateUser(auditorId);
        rao.setUpdateTime(new Date());
        if (rao.getCreateUser() == null) {
            rao.setCreateUser(rao.getUpdateUser());
            rao.setCreateTime(rao.getUpdateTime());
        }
    }

    public void setAuditOperationDao(IAuditOperationDao auditOperationDao) {
        this.auditOperationDao = auditOperationDao;
    }

    public void setAuditRuleDao(IAuditRuleDao auditRuleDao) {
        this.auditRuleDao = auditRuleDao;
    }

    public void submit(AuditOperandType auditOperandType, long auditOperandId,
            Account account) throws AuditException {
        String auditorId = account.getId().toString();
        Long accountId = null;
        if (isCorpAccount(account)) { // 企业客户设置accountId，以查找该客户下的审核规则
            accountId = account.getId();
        }
        submit(auditOperandType, auditOperandId, accountId, auditorId);
    }
    
    /**
     * 区别公司资料审核
     * @param auditOperandType
     * @param auditOperandId
     * @param account
     * @param auditType
     * @throws AuditException
     */
    public void submit(AuditOperandType auditOperandType, long auditOperandId,
            Account account,boolean auditType) throws AuditException {
        String auditorId = account.getId().toString();
        Long accountId = null;
        submit(auditOperandType, auditOperandId, accountId, auditorId);
    }

    private boolean isCorpAccount(Account account) {
        return Constant.ACCOUNT_TYPE_CORPORATION.equals(account
                .getAccountType());
    }

    private void submit(AuditOperandType auditOperandType, long auditOperandId,
            Long accountId, String auditorId) throws AuditException {
        RecentAuditOperation rao = getRecentAuditOperation(auditOperandType,
                auditOperandId);
        if (rao == null) {
            create(auditOperandType, auditOperandId, accountId, auditorId);
            agree(auditOperandType, auditOperandId, auditorId, null);
        } else { // rao不为空，则交易肯定是需要审核的
            AuditStatus auditStatus = new AuditOperationWrapper(rao)
                    .getPostStatus();
            // 只有初始状态和被拒绝的审核对象才能进行提交操作
            if (auditStatus != AuditStatus.STATUS_PRIMARY
                    && auditStatus != AuditStatus.STATUS_REJECTED) {
                throw AuditException.AUDIT_STATUS_MISMATCH;
            }
            agree(auditOperandType, auditOperandId, auditorId, null);
        }
    }

    public void submit(AuditOperandType auditOperandType, long auditOperandId,
            Operator operator) throws AuditException {
        Long accountId = operator.getAccount().getId();
        String auditorId = operator.getId().toString();
        submit(auditOperandType, auditOperandId, accountId, auditorId);
    }

    public void submit(AuditOperandType auditOperandType, long auditOperandId,
            UserInfo user) throws AuditException {
        String auditorId = user.getId().toString();
        submit(auditOperandType, auditOperandId, null, auditorId);
    }

    private void update(RecentAuditOperation auditOperation) {
        long auditOperandId = auditOperation.getAuditOperandId().longValue();
        AuditOperandType auditOperandType = auditOperation.getAuditRule()
                .getAuditOperandType();
        AuditOperation[] historyOperations = getHistoryAuditOperations(
                auditOperandType, auditOperandId);
        HistoryAuditOperation lastHistoryOperation = historyOperations.length == 0 ? null
                : (HistoryAuditOperation) historyOperations[historyOperations.length - 1];
        long sequenceNo = new HistoryAuditOperationWrapper(lastHistoryOperation)
                .nextAuditSequenceNo();
        HistoryAuditOperation historyOperation = HistoryAuditOperationWrapper
                .getHistoryAuditOperation(sequenceNo, auditOperation);
        auditOperation.getAuditRule().setUsed(Constant.USED_YES);
        this.auditOperationDao.saveOrUpdateAuditOperation(auditOperation);
        this.auditOperationDao.saveOrUpdateAuditOperation(historyOperation);
    }

    private boolean validAuditRule(AuditRule auditRule) {
        if (auditRule == null)
            return false;
        return auditRule.getAuditSteps().size() > 0
                && Constant.VALID_YES == auditRule.getValid();
    }

}
